import traceback
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from sqlalchemy.sql import func

from app.common.exceptions import GenericException
from app.common.enums.resp_enum import ErrTypes
from app.common.enums.bz_enum import SubAccType
from app.models.report.trans_report import DailyTransReport
from app.models import PayOrder
from app import utils
from app.services.order import get_order_query_set_between_datetime

import logging
logger = logging.getLogger(__name__)

def gen_and_save_daily_trans_reports(db: Session, start: datetime=None, end: datetime=None, delta: timedelta=None):
    logger.info('>> 批量生成日报数据')
    if delta is None:
        delta: timedelta = end - start
    result_list = []
    for i in range(0, delta.days):
        start_offset = timedelta(days=i)
        i_start_dt = start + start_offset
        i_end_dt = utils.time.get_next_day_zero_time(i_start_dt)
        report_data = gen_and_save_daily_trans_report(db, start=i_start_dt, end=i_end_dt)
        logger.info(f'report_data: {report_data}')
        result_list.append(report_data.get('trans_date'))
    return result_list

def gen_and_save_daily_trans_report(db: Session, start: datetime=None, end: datetime=None):
    if not start:
        start = utils.time.get_date_zero_time()
    if not end:
        end = datetime.now()
    report_data = gen_daily_trans_report_data(db, start, end)
    save_daily_trans_report(db, report_data)
    return report_data

def gen_daily_trans_report_data(db: Session, start: datetime=None, end: datetime=None):
    logger.info('>> 获取日订单数据')
    if not start:
        start = utils.time.get_date_zero_time()
    if not end:
        end = datetime.now()
    total_set = get_order_query_set_between_datetime(db, start, end)
    success_set = total_set.filter_by(status = 1)
    failed_set = total_set.filter_by(status = 2)
    profit_processed_set = total_set.filter_by(is_profit_processed = 'Y')

    #total_num = total_set.with_entities(func.count(PayOrder.order_no)).scalar() or 0
    total_num = total_set.count()
    total_amt = total_set.with_entities(func.sum(PayOrder.amount)).scalar() or 0
    total_fee = success_set.with_entities(func.sum(PayOrder.fee)).scalar() or 0

    success_num = success_set.count()
    success_amt = success_set.with_entities(func.sum(PayOrder.amount)).scalar() or 0
    failed_num = failed_set.count()
    profit_processed_num = profit_processed_set.count()
    #profit_amt = query_set.with_entities(func.sum(PayOrder.amount)).scalar() or 0

    resp_data = {
        'trans_date': utils.fmt_time(start, type=5),
        'total_num': total_num,
        'success_num': success_num,
        'total_amt': int(total_amt),
        'total_fee': int(total_fee),
        'success_amt': int(success_amt),
        'failed_num': failed_num,
        'profit_processed_num': profit_processed_num,
    }
    return resp_data

def save_daily_trans_report(db: Session, report_data: dict):
    try:
        trans_date = report_data.get('trans_date')
        report = db.query(DailyTransReport).filter_by(trans_date = trans_date).first()
        if not report:
            report = DailyTransReport(trans_date = trans_date)
        report.total_num = report_data.get('total_num')
        report.success_num = report_data.get('success_num')
        report.failed_num = report_data.get('failed_num')
        report.total_amt = report_data.get('total_amt')
        report.success_amt = report_data.get('success_amt')
        report.total_fee = report_data.get('total_fee')
        report.failed_num = report_data.get('failed_num')
        report.profit_processed_num = report_data.get('profit_processed_num')
        db.add(report)
        db.commit()
        return True
    except GenericException as err:
        logger.error('Error: %s' % err.message)
        raise GenericException(err.error_type, message='保存日报数据失败')
    except Exception as err:
        logger.exception('保存日报数据失败', stack_info=True, stacklevel=3)
        #logger.error(traceback.print_exc)
        raise GenericException(ErrTypes.db_save_fail)
    
def get_trans_report_data(db: Session, days: int=None, start: str=None, end: str=None):
    try:
        if days:
            tdelta = timedelta(days=days)
            dt_today = utils.time.get_date_zero_time()
            start_dt = dt_today - tdelta
            end_dt = utils.time.get_next_day_zero_time()
        else:
            if start:
                start_dt = utils.time.str_to_time(start, 5)
            else:
                start_dt = utils.time.get_date_zero_time()
            if end:
                end_dt = utils.time.str_to_time(end, 5)
            else:
                end_dt = utils.time.get_next_day_zero_time()
        start_date_str = utils.fmt_time(start_dt, 5)
        end_date_str = utils.fmt_time(end_dt, 5)
        results = db.query(DailyTransReport).filter(
            DailyTransReport.trans_date > start_date_str,
            DailyTransReport.create_time < end_date_str
        ).all()
        return results
    except GenericException as err:
        logger.error('Error: %s' % err.message)
        raise GenericException(err.error_type)
    except Exception as err:
        logger.exception(err)
        #logger.error(traceback.print_exc)
        raise GenericException(ErrTypes.db_query_error)
    



